package block

import (
	"errors"
	"fmt"
	bolt "github.com/boltdb/github-boltdb-master"
)

/**
 ** @author: hui
 ** @email: 3231954428@qq.com
 ** @phone: 15779563913
 ** @DataTime: 2022/2/25 10:32
 **/

type Chain struct {
	//Blocks		[]*Block
	DB			*bolt.DB
	LastHash	[]byte
}

//常数
const CHAIN_DB_PATH = "./chain.db"
const BUKET_BLOCK = "chain_block"
const BUKEY_STATUS = "chain_status"
const LAST_HASH = "last_hash"

/**
创建区块链o
 */

func NewBlockChain(data []byte) (*Chain, error) {

	open, err := bolt.Open(CHAIN_DB_PATH, 0600, nil)
	if err != nil{
		return nil, err
	}

	var lastHash []byte

	err = open.Update(func(tx *bolt.Tx) error {
		//保存区块
		bucket := tx.Bucket([]byte(BUKET_BLOCK))
		//没有桶
		if bucket == nil{
			gennesis := GenesisBlock(data)
			//创建桶
			cb, err := tx.CreateBucket([]byte(BUKET_BLOCK))
			if err != nil{
				return err
			}
			//把创世区块序列化
			serialize, err := gennesis.Serialize()
			if err != nil {
				return err
			}
			cb.Put(gennesis.Hash, serialize)
			//创建桶2，保存区块的hash
			cb2, err := tx.CreateBucket([]byte(BUKEY_STATUS))
			if err != nil {
				return err
			}
			cb2.Put([]byte(LAST_HASH), gennesis.Hash)
			lastHash = gennesis.Hash
		} else {
			cb2 := tx.Bucket([]byte(BUKEY_STATUS))
			hash := cb2.Get([]byte(LAST_HASH))
			lastHash = hash
		}
		return nil
	})

	//初始化并实例化
	bc := Chain{
		DB: open,
		LastHash: lastHash,
	}
	return &bc, nil

}

/**
向区块链里添加新区块
 */

func (bc *Chain)AddBlock(data []byte) error{
	//创建新区块
	NewBlock := NewBlock(data, bc.LastHash)
	//添加到数据库中
	err := bc.DB.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(BUKET_BLOCK))
		if bucket == nil{
			return errors.New("没有桶1")
		}
		serialize, err := NewBlock.Serialize()
		if err != nil{
			return err
		}
		//存数据
		bucket.Put(NewBlock.Hash, serialize)

		bucket2 := tx.Bucket([]byte(BUKEY_STATUS))
		if bucket2 == nil{
			return errors.New("没有桶2")
		}
		bucket2.Put([]byte(LAST_HASH), NewBlock.Hash)
		bc.LastHash = NewBlock.Hash
		return nil

	})

	return err
}

/**
创建迭代器
*/

func (bc *Chain) Iterator() *ChainIterator{

	iterator := ChainIterator{
		DB:				bc.DB,
		CurrentHash: 	bc.LastHash,
	}

	return &iterator
}

//获取所有区块对象
func (bc *Chain) GetAllBlock() []*Block {

	block := []*Block{}
	//迭代器
	iterator := bc.Iterator()
	for iterator.HasNext(){
		blocks, err := iterator.Next()
		if err != nil{
			fmt.Println(err.Error())
			return nil
		}
		block = append(block, blocks)
	}

	return block
}


